package domain;

import java.util.ArrayList;

/*
 * Holds the gamegrid, wich is filled with squares.
 */
/*
 * IMPLEMENTATION STATUS - Set start values. - Update values after move. -
 * Initiate values, if needed else just use updateGameValues.
 */
public class GameGrid
{

    private static int xSize = 8;
    private static int ySize = 8;
    public Square GameGrid[][];
    public int ValueGrid[][] = {
        {10000, -3000, 1000, 800, 800, 10000, -3000, 10000},
        {-3000, -5000, -450, -500, -500, -450, -5000, -3000},
        {1000, -450, 30, 10, 10, 30, -450, 1000},
        {800, -500, 10, 50, 50, 10, -500, 800},
        {800, -500, 10, 50, 50, 10, -500, 800},
        {1000, -450, 30, 10, 10, 30, -450, 1000},
        {-3000, -5000, -450, -500, -500, -450, -5000, -3000},
        {10000, -3000, 1000, 800, 800, 10000, -3000, 10000}
    };

    // Constructor.
    public GameGrid()
    {
        GameGrid = new Square[8][8];
        initiateGameGrid();
    }

    public void printGrid()
    {
        for (int y = 0; y < 8; y++) {
            for (int x = 0; x < 8; x++) {
                System.out.print("[" + GameGrid[x][y].getOwner() + "]");
            }
            System.out.println("");
        }
        System.out.println("----------------------------");
    }
    // Initate a starting board.

    private void initiateGameGrid()
    {
        for (int x = 0; x < xSize; x++) {
            for (int y = 0; y < ySize; y++) {
                GameGrid[x][y] = new Square(0);
            }
        }
        // Initate start squares.
        // Player 1(White).
        GameGrid[3][3].setOwner(2);
        GameGrid[4][4].setOwner(2);
        //GameGrid[2][2].setOwner(1);


        // Player 2(Black).
        GameGrid[3][4].setOwner(1);
        GameGrid[4][3].setOwner(1);

    }

    // Inserts a move at the choosen x,y possition.
    public void insertMove(int x, int y, int playerID)
    {
        GameGrid[x][y].setOwner(playerID);
        //updateGameGridValues();
    }

    //utgår ifrån att man redan vet att draget är tillåtet
    public void makeMove(int playerId, int x, int y)
    {
        GameGrid[x][y].setOwner(playerId);

        flip(playerId, x, y - 1, 1);//N
        flip(playerId, x + 1, y - 1, 2);//NE
        flip(playerId, x + 1, y, 3);//E
        flip(playerId, x + 1, y + 1, 4);//SE
        flip(playerId, x, y + 1, 5);//S
        flip(playerId, x - 1, y + 1, 6);//SW
        flip(playerId, x - 1, y, 7);//W
        flip(playerId, x - 1, y - 1, 8);//NW

    }

    //anropas bara från makeMove
    private boolean flip(int playerId, int x, int y, int compass)
    {
        if (x < 0 || y < 0 || x > 7 || y > 7) {
            return false;
        }
        switch (compass) {
            case 1://N
                if (goldenRule(playerId, x, y, compass)) {
                    for (int y2 = y; y2 >= 0; y2--) {
                        if (GameGrid[x][y2].isOponent(playerId)) {
                            GameGrid[x][y2].setOwner(playerId);
                        } else if (GameGrid[x][y2].getOwner() == playerId) {
                            return true;//avbryt när vi hittar en egen
                        }
                    }
                }
                break;
            case 2://NE
                int xNE = x;
                if (goldenRule(playerId, x, y, compass)) {
                    for (int y2 = y; y2 >= 0; y2--) {

                        if (xNE < 8) {
                            if (GameGrid[xNE][y2].isOponent(playerId)) {
                                GameGrid[xNE][y2].setOwner(playerId); //vi får inte "hoppa över" tomma rutor
                            } else if (GameGrid[xNE][y2].getOwner() == playerId) {
                                return true; //avbryt när vi hittar en egen
                            }
                            xNE++;
                        }
                    }
                }
                break;
            case 3://E
                if (goldenRule(playerId, x, y, compass)) {
                    for (int x2 = x; x2 < 8; x2++) {
                        if (GameGrid[x2][y].isOponent(playerId)) {
                            GameGrid[x2][y].setOwner(playerId); //vi får inte "hoppa över" tomma rutor
                        } else if (GameGrid[x2][y].getOwner() == playerId) {
                            return true; //vi hittade en av våra egna och har skapat en macka! (no homo)
                        }
                    }
                }
                break;
            case 4://SE
                if (goldenRule(playerId, x, y, compass)) {
                    int xSE = x;
                    for (int y2 = y; y2 < 8; y2++) {

                        if (xSE < 8) {
                            if (GameGrid[xSE][y2].isOponent(playerId)) {
                                GameGrid[xSE][y2].setOwner(playerId); //vi får inte "hoppa över" tomma rutor
                            } else if (GameGrid[xSE][y2].getOwner() == playerId) {
                                return true; //vi hittade en av våra egna och har skapat en macka! (no homo)
                            }
                            xSE++;
                        }
                    }
                }
                break;
            case 5://S
                if (goldenRule(playerId, x, y, compass)) {
                    for (int y2 = y; y2 < 8; y2++) {
                        if (GameGrid[x][y2].isOponent(playerId)) {
                            GameGrid[x][y2].setOwner(playerId); //vi får inte "hoppa över" tomma rutor
                        } else if (GameGrid[x][y2].getOwner() == playerId) {
                            return true; //vi hittade en av våra egna och har skapat en macka! (no homo)
                        }
                    }
                }
                break;
            case 6://SW
                int xSW = x;
                if (goldenRule(playerId, x, y, compass)) {
                    for (int y2 = y; y2 < 8; y2++) {

                        if (xSW >= 0) {

                            if (GameGrid[xSW][y2].isOponent(playerId)) {
                                GameGrid[xSW][y2].setOwner(playerId); //vi får inte "hoppa över" tomma rutor
                            } else if (GameGrid[xSW][y2].getOwner() == playerId) {
                                return true; //vi hittade en av våra egna och har skapat en macka! (no homo)
                            }
                            xSW--;
                        }
                    }
                }
                break;
            case 7://W
                if (goldenRule(playerId, x, y, compass)) {
                    for (int x2 = x; x2 >= 0; x2--) {
                        if (GameGrid[x2][y].isOponent(playerId)) {
                            GameGrid[x2][y].setOwner(playerId); //vi får inte "hoppa över" tomma rutor
                        } else if (GameGrid[x2][y].getOwner() == playerId) {
                            return true; //vi hittade en av våra egna och har skapat en macka! (no homo)
                        }
                    }
                }
                break;
            case 8://NW
                int xNW = x;
                if (goldenRule(playerId, x, y, compass)) {
                    for (int y2 = y; y2 >= 0; y2--) {

                        if (xNW >= 0) {
                            //for (int x2 = x; x2 >= 0; x2--) {
                            if (GameGrid[xNW][y2].isOponent(playerId)) {
                                GameGrid[xNW][y2].setOwner(playerId); //vi får inte "hoppa över" tomma rutor
                            } else if (GameGrid[xNW][y2].getOwner() == playerId) {
                                return true; //vi hittade en av våra egna och har skapat en macka! (no homo)
                            }
                            xNW--;
                            //}

                        }
                    }
                    break;
                }

        }
        return true;
    }

    public boolean isTerminalState(int playerId)
    {
        for (int y = 0; y < 8; y++) {
            for (int x = 0; x < 8; x++) {
                if (GameGrid[x][y].getOwner() == 0) {
                    if (isLegalMove(playerId, x, y)) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    public boolean isTerminalState()
    {
        if (isTerminalState(1)) {
            if (isTerminalState(2)) {
                return true;
            }
        }
        return false;
    }

    //returnera PlayerId eller 0 om oavgjort
    public int GetWinner()
    {
        int p1 = 0;
        int p2 = 0;
        for (int y = 0; y < 8; y++) {
            for (int x = 0; x < 8; x++) {
                if (GameGrid[x][y].getOwner() == 1) {
                    p1++;
                } else if (GameGrid[x][y].getOwner() == 2) {
                    p2++;
                }
            }
        }
        if (p1 > p2) {
            return 1;
        } else if (p2 > p1) {
            return 2;
        }
        return 0;
    }

    //returnerar antalt brickor som spelaren har
    public int getCount(int playerId)
    {
        int i = 0;
        for (int y = 0; y < 8; y++) {
            for (int x = 0; x < 8; x++) {
                if (GameGrid[x][y].getOwner() == playerId) {
                    i++;
                }
            }
        }
        return i;
    }

    //Ett move är tillåtet om rutan är ledig och
    //spelaren som ska lägga draget har en bricka
    //på en ruta som är i linje med rutan och
    //rutan ligger brevid en motståndarbricka
    private boolean isAdjacentMove(int playerId, int x1, int y1, int x2, int y2)
    {
        //out of bounce
        if (x2 < 0 || y2 < 0 || x2 > 7 || y2 > 7) {
            return false;
        }
        if (playerId == 1) {
            if (GameGrid[x2][y2].getOwner() == 2) {
                return true;
            }
        }
        if (playerId == 2) {
            if (GameGrid[x2][y2].getOwner() == 1) {
                return true;
            }
        }
        //else
        return false;
    }

    private boolean goldenRule(int playerId, int x, int y, int compass)
    {
        //its not gay if its in a threeway

        //hantera out of bounce
        if (x < 0 || y < 0 || x > 7 || y > 7) {
            return false;
        }

        switch (compass) {
            case 1://N
                for (int y2 = y; y2 >= 0; y2--) {
                    if (GameGrid[x][y2].getOwner() == 0) {
                        return false; //vi får inte "hoppa över" tomma rutor
                    }
                    if (GameGrid[x][y2].getOwner() == playerId) {
                        return true; //vi hittade en av våra egna och har skapat en macka! (no homo)
                    }
                }
                break;
            case 2://NE
                int xNE = x;
                for (int y2 = y; y2 >= 0; y2--) {

                    if (xNE < 8) {
                        if (GameGrid[xNE][y2].getOwner() == 0) {
                            return false; //vi får inte "hoppa över" tomma rutor
                        }
                        if (GameGrid[xNE][y2].getOwner() == playerId) {
                            return true; //vi hittade en av våra egna och har skapat en macka! (no homo)
                        }
                        xNE++;
                    } else {
                        return false;
                    }

                }
                break;
            case 3://E
                for (int x2 = x; x2 < 8; x2++) {
                    if (GameGrid[x2][y].getOwner() == 0) {
                        return false; //vi får inte "hoppa över" tomma rutor
                    }
                    if (GameGrid[x2][y].getOwner() == playerId) {
                        return true; //vi hittade en av våra egna och har skapat en macka! (no homo)
                    }
                }
                break;
            case 4://SE

                int xSE = x;
                for (int y2 = y; y2 < 8; y2++) {

                    if (xSE < 8) {
                        if (GameGrid[xSE][y2].getOwner() == 0) {
                            return false; //vi får inte "hoppa över" tomma rutor
                        }
                        if (GameGrid[xSE][y2].getOwner() == playerId) {
                            return true; //vi hittade en av våra egna och har skapat en macka! (no homo)
                        }
                        xSE++;

                    } else {
                        return false;
                    }

                }
                break;
            case 5://S
                for (int y2 = y; y2 < 8; y2++) {
                    if (GameGrid[x][y2].getOwner() == 0) {
                        return false; //vi får inte "hoppa över" tomma rutor
                    }
                    if (GameGrid[x][y2].getOwner() == playerId) {
                        return true; //vi hittade en av våra egna och har skapat en macka! (no homo)
                    }
                }
                break;
            case 6://SW
                int xSW = x;
                for (int y2 = y; y2 < 8; y2++) {

                    if (xSW >= 0) {

                        if (GameGrid[xSW][y2].getOwner() == 0) {
                            return false; //vi får inte "hoppa över" tomma rutor
                        }
                        if (GameGrid[xSW][y2].getOwner() == playerId) {
                            return true; //vi hittade en av våra egna och har skapat en macka! (no homo)
                        }
                        xSW--;

                    } else {
                        return false;
                    }

                }
                break;
            case 7://W
                for (int x2 = x; x2 >= 0; x2--) {
                    if (GameGrid[x2][y].getOwner() == 0) {
                        return false; //vi får inte "hoppa över" tomma rutor
                    }
                    if (GameGrid[x2][y].getOwner() == playerId) {
                        return true; //vi hittade en av våra egna och har skapat en macka! (no homo)
                    }
                }
                break;
            case 8://NW
                int xNW = x;
                for (int y2 = y; y2 >= 0; y2--) {

                    if (xNW >= 0) {
                        //for (int x2 = x; x2 >= 0; x2--) {
                        if (GameGrid[xNW][y2].getOwner() == 0) {
                            return false; //vi får inte "hoppa över" tomma rutor
                        }
                        if (GameGrid[xNW][y2].getOwner() == playerId) {
                            return true; //vi hittade en av våra egna och har skapat en macka! (no homo)
                        }
                        xNW--;
                        //}
                    } else {
                        return false;
                    }
                }
                break;
        }

        return false;
    }

    public boolean isLegalMove(int playerId, int x, int y)
    {

        boolean bit = false;

        //är rutan ledig?
        if (GameGrid[x][y].getOwner() != 0) {
            return false;
        }

        //ligger den brevid en motståndare?
        //NW
        if (isAdjacentMove(playerId, x, y, x - 1, y - 1)) {
            if (goldenRule(playerId, x - 2, y - 2, 8)) {
                bit = true;
            }
        }
        //N
        if (isAdjacentMove(playerId, x, y, x, y - 1)) {
            if (goldenRule(playerId, x, y - 2, 1)) {
                bit = true;
            }
        }
        //NE
        if (isAdjacentMove(playerId, x, y, x + 1, y - 1)) {
            if (goldenRule(playerId, x + 2, y - 2, 2)) {
                bit = true;
            }
        }
        //W
        if (isAdjacentMove(playerId, x, y, x - 1, y)) {
            if (goldenRule(playerId, x - 2, y, 7)) {
                bit = true;
            }
        }
        //E
        if (isAdjacentMove(playerId, x, y, x + 1, y)) {
            if (goldenRule(playerId, x + 2, y, 3)) {
                bit = true;
            }
        }
        //SW
        if (isAdjacentMove(playerId, x, y, x - 1, y + 1)) {
            if (goldenRule(playerId, x - 2, y + 2, 6)) {
                bit = true;
            }
        }
        //S
        if (isAdjacentMove(playerId, x, y, x, y + 1)) {
            if (goldenRule(playerId, x, y + 2, 5)) {
                bit = true;
            }
        }
        //SE
        if (isAdjacentMove(playerId, x, y, x + 1, y + 1)) {
            if (goldenRule(playerId, x + 2, y + 2, 4)) {
                bit = true;
            }
        }

        if (!bit) {
            return false;
        }

        return true;
    }

    public int getValueUtility(int playerId)
    {
        int utility = 0;
        int delta = 0;
        int oponentMoves = 0;
        int total = 0;
        int moveUtilityWeight = 100;



        for (int y = 0; y < 8; y++) {
            for (int x = 0; x < 8; x++) {

                if (GameGrid[x][y].getOwner() == 0) {
                    if (isLegalMove(oponentOf(playerId), x, y)) {
                        oponentMoves += 1;
                    }
                }

                if (GameGrid[x][y].getOwner() == playerId) {
                    utility += ValueGrid[x][y];
                }
            }
        }
        total = (oponentMoves * -1) * moveUtilityWeight;
        //return utility-delta;
        return (utility - delta);// + total;
    }

    public int getValueUtility(int playerId, int newX, int newY)
    {
        int utility1 = 0;
        int utility2 = 0;
        int delta = 0;
        int oponentMoves = 0;
        int myMoves = 0;
        int total = 0;
        int moveUtilityWeight = 100;



        for (int y = 0; y < 8; y++) {
            for (int x = 0; x < 8; x++) {

                if (GameGrid[x][y].getOwner() == oponentOf(playerId)) {
                    //if (isLegalMove(oponentOf(playerId), x, y)) {
                    //    oponentMoves += 1;
                    //}
                    if (ValueGrid[x][y] < utility2) {
                        utility2 = (utility2) + (ValueGrid[x][y]);
                    } else {
                        utility2 = (ValueGrid[x][y]) + (utility2);
                    }
                }
                /*
                 * if(isLegalMove(oponentOf(playerId),x,y)){ oponentMoves++; }
                 * if(isLegalMove(playerId,x,y)){ myMoves++; }
                 */

                if (GameGrid[x][y].getOwner() == playerId) {
                    if (ValueGrid[x][y] < utility1) {
                        utility1 = (utility1) + (ValueGrid[x][y]);
                    } else {
                        utility1 = (ValueGrid[x][y]) + (utility1);
                    }
                    //utility1++;
                }
            }
        }
        total = (oponentMoves * -1) * moveUtilityWeight;
        //return utility-delta;
        // System.out.println("x:" + newX+" y:"+newY+" = "+ValueGrid[newX][newY]);
        return utility1 + (myMoves * moveUtilityWeight) - (utility2) * -1 - (oponentMoves * moveUtilityWeight); //+ ValueGrid[newX][newY];// + total;
    }

    private int oponentOf(int playerId)
    {
        if (playerId == 1) {
            return 2;
        }
        return 1;
    }
}
